-- local stderr = io.open('d:/src/windows/func','w+');
function getDumpFunctions(f,ffunc)
    local functions = {};
    local len = 0;
    if(f)then len = #f;end;
    for k,v in ipairs(function_decl)do
        local func = v:GetDecl();
        local src,line = func:GetFilePosition();
        if(dumpSourceFlag and dumpSource[src])then
            table.insert(functions,func);
        elseif(f==nil and ffunc==nil)then
            table.insert(functions,func);
        elseif(f==nil)then
            if(dumpSourceFlag)then
            else
                table.insert(functions,func);
            end
        else
            local name = func.name.strg;
            --if(name==nil)then name = "";end;
            -- stderr:write(tostring(func.name.strg),'\n');

            if(name~=nil and(f == name:sub(1,len) or ffunc(name,v)))then
                table.insert(functions,func);
            end
        end
    end

    table.sort(functions,function(a,b)
        local an = a.name.strg;
        local bn = b.name.strg;
        --print(an,bn);
        if(an==nil)then return false;end;
        if(bn==nil)then return false;end;
        return an<bn;
    end
    );
    return functions;
end

function exportFunc(def)
    if(def.func_out==nil)then def.func_out = io.tmpfile(); end;
    local out = def.func_out;
    local funcNames = {};
    local f = def.filter;
    local functions = getDumpFunctions(f,isDump);
    local structs = {};

    for k,v in ipairs(functions) do
        local f = v:GetFunction();
        if(f.name)then
            if(Remove[f.name]~=nil)then
                --需要移除的函数
                out:write(string.format("\n//remove function %s\n\n\n",f.name));
            else
                --添加到函数表
                table.insert(funcNames,f.name);

                local nodump = false;
                local args = '';
                local comma = '';
                -- if(#f.args>=1)then
                --     out:write(f.args[1].id);
                -- end
                --print(f.name,f.code);
                for kk,vv in ipairs(f.args)do
                    local type,name,ref = vv:GetParmInfo();
                    if(name==nil)then
                        name = 'a' .. kk;
                    end
                    if(ref~=0)then
                        local s = '**********';
                        ref = s:sub(1,ref);
                    else
                        ref = '';
                    end
                    local struct = 'struct ';
                    local const_type = '';
                    if(type:IsAliasStruct())then
                        struct = '';
                    end
                    
                    if(type:IsBaseType())then
                        struct = '';
                    else
                        local name = type:GetTypeName();
                        structs[name] = type;
                    end
                    if(type:IsConstType())then
                        const_type = 'const ';
                    end
                    if(type:IsRefType())then
                        nodump = true;
                        break;
                    end
                    args = string.format('%s%s%s%s %s%s',args,comma,const_type,struct .. type:GetTypeName(),ref,name);
                    comma = ','
                end
                local nodefstruct = true;
                local retn = f.retn:GetTypeNameC(nodefstruct);
                if(retn ==nil or retn:sub(1,3)=='nil')then
                    print(f.retn.id);
                end
                if(f.retn:IsRefType() or v.lang~='C')then
                    nodump = true;
                end
                --out:write(f.retn.id..'\n');
                if(tostring(f.name):sub(1,2)=='SH')then
                    print(f.name,nodump,f.retn:IsRefType(),v.lang,v.id);
                end
                local s = string.format('%s %s(%s);\n',retn,f.name,args);
                if(nodump==false)then
                    out:write(s);
                end
            end
        end
    end
    def.structs = structs;
end

local function readText(f)
    f:seek('set');
    return f:read('*a');
end

function depend(structs)

end

function outStruct(file,structs)
    local out = file;
    --解决结构体的依赖
    local list = {};
    for k,v in pairs(structs) do
        table.insert(list,v);
    end

    table.sort(list,function(a,b)
        return a.id<b.id;
    end);
    structs = list;
    local outFields;

    local dumpstructs = {};
    local function out_struct(file,typ)
        if(dumpstructs[typ])then
            return;
        end
        local out = io.tmpfile();
        local v = typ;
        local b = v:GetAliasTypeBaseStruct();
        if(b~=nil)then
            name = b:GetTypeName();
            if(dumpstructs[b])then
                if(dumpstructs[typ]==nil)then
                    file:write(string.format('typedef %s %s;\n',b:GetTypeNameC(),typ:GetTypeName()));
                end
                return;
            end
            file:write(string.format('typedef %s %s;\n',b:GetTypeNameC(),typ:GetTypeName()));
            typ = b;
        else
            name = v:GetTypeName();
        end

        if(name=='IWindowForBindingUI')then
            print(v.id);
        end
        if(typ.vfld)then
            print(v.id,v:GetTypeNameC());
            return;
        end

        out:write(string.format('struct %s',name));
        outFields(file,v,out);
        out:write(string.format(';\n'));
        file:write(readText(out));
        dumpstructs[typ] = true;
        out:close();
    end
    
    outFields = function(file,typ,structfile)
        local out = structfile;
        if(typ:IsFunctionType())then return; end;
        out:write('{\n')
        local next,name,type,bpos,size,algn = typ:GetTypeNextFieldInfo();
        assert(type,'error type fileds'..typ.id);
        while(true)do
            --print(type.id,type:GetTypeNameC());
            if(name)then
                if(type:IsBitType())then break; end;
                local n,array = type:GetTypeNameC();
                --if(n:sub(1,3)=='nil')then print(type.id); end;
                if(array)then array = string.format('[%d]',array); 
                else array = ''; end;

                if(type:IsStruct())then
                    def = 1;
                    out_struct(file,type);
                    def = nil;
                end

                out:write(string.format('%s %s%s;\n',n,name,array));
            else
                --匿名结构体
                if(type:IsUnionType())then
                    out:write(string.format('union\n'));
                elseif(type:IsRecordType())then
                    out:write(string.format('struct\n'));
                else
                    assert(nil,'error types');
                end
                outFields(file,type,structfile);
                out:write(';\n')
            end
            if(next==nil)then break; end;
            next,name,type,bpos,size,algn = next:GetTypeNextFieldInfo();
        end
        out:write('}');
    end
    for k,v in pairs(structs)do
        --创建一个基础结构体
        if(v:IsAliasStruct())then
            local b = v:GetAliasTypeBaseStruct();
            local name = 'stag'..v:GetTypeName();
            if(b~=nil)then
                name =  b:GetTypeName();
            end
            out:write(string.format('struct %s;\n',name));
            out:write(string.format('typedef struct %s %s;\n',name,v:GetTypeName()));
        else
            out:write(string.format('struct %s;\n',v:GetTypeName()));
        end
    end

    for k,v in ipairs(structs)do

            -- local b = v:GetAliasTypeBaseStruct();
            -- local name = 'stag'..v:GetTypeName();
            -- if(b~=nil)then
            --     name =  b:GetTypeName();
            -- end

            -- out:write(string.format('struct %s',name));
            -- outFields(out,v);
            -- out:write(string.format(';\n'));
            out_struct(out,v);

    end
end

function ljitEnd(def)
    if(def.outfile)then
        
        local out = def.outfile;
        if(type(out)=='string')then
            out = io.open(out,'w+');
        end
        if(def.structs)then
            out:write('typedef short wchar_t;\n');
            --outStruct(out,def.structs);
        end
        if(def.func_out)then
            out:write(readText(def.func_out));
        end
    end
end


local luajitDef = {
    exportFunction = exportFunc,
    exportType = ljitType,
    exportEnum = ljitEnum,
    exportEnd = ljitEnd,
}

return luajitDef;
